﻿using System;
using System.Net;
using Catchbase.TestTools;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Catchbase.Service.API.UTest
{
    [TestClass]
    public class ServiceClientTest : TestBase<ServiceClient<TestObject>>
    {
        private Mock<HttpWebRequestGateway> _request;
        private Uri _uri;
        private TestObject _domainObject;
        private Mock<HttpWebResponseGateway> _response;
        private string _url = "http://localhost/catchlist";
        private SecurityManager _securityManager;
        private WebHeaderCollection _requestHeaders;

        protected override void InitializeTest()
        {
            _securityManager = new SecurityManager("some@email.com", "sharedsecret");
            _uri = new Uri(_url);
            _domainObject = new TestObject();
            _response = new Mock<HttpWebResponseGateway>();
            _request = new Mock<HttpWebRequestGateway>();
            _requestHeaders = new WebHeaderCollection();
            _request.Setup(r => r.Headers).Returns(_requestHeaders);
            _request.Setup(r => r.GetResponse()).Returns(_response.Object);
            Mock<RequestBuilder>().Setup(r => r.Build(It.IsAny<HttpMethod>(), It.IsAny<Uri>())).Returns(_request.Object);
            Mock<JsonHelper>().Setup(h => h.Read<TestObject>(It.IsAny<HttpWebResponseGateway>())).Returns(_domainObject);
            Mock<CatchbaseUriBuilder>().Setup(b => b.Build<TestObject>()).Returns(_uri);
        }

        [TestMethod]
        public void Get_MustReturnItemOfT()
        {
            Subject.Get().MustBeSame(_domainObject);
        }

        [TestMethod]
        public void Get_MustAddAuthorizationToRequest_WhenSecuritymanagerIsProvided()
        {
            Subject.Get(_securityManager);
            _requestHeaders.Get("Authorization").MustStartWith("Basic ");
        }

        [TestMethod]
        public void Get_MustUseMethodGet()
        {
            Subject.Get();
            Mock<RequestBuilder>().Verify(b => b.Build(HttpMethod.GET, It.IsAny<Uri>()), Times.Once());
        }

        [TestMethod]
        public void Get_MustUseUri()
        {
            Subject.Get();
            Mock<RequestBuilder>().Verify(b => b.Build(It.IsAny<HttpMethod>(), _uri), Times.Once());
        }

        [TestMethod]
        public void Post_MustGetResponse()
        {
            Subject.Post(new TestObject());
            _request.Verify(r => r.GetResponse(), Times.Once());
        }

        [TestMethod]
        public void Post_MustAddAuthorizationToRequest_WhenSecuritymanagerIsProvided()
        {
            Subject.Post(new TestObject(), _securityManager);
            _requestHeaders.Get("Authorization").MustStartWith("Basic ");
        }

        [TestMethod]
        public void Post_MustWriteObjectToRequestStream()
        {
            var item = new TestObject();
            Subject.Post(item);
            Mock<JsonHelper>().Verify(j => j.Write(_request.Object, item), Times.Once());
        }

        [TestMethod]
        public void Get_MustBuildUriWithId_WhenIdIsProvided()
        {
            var uri = new Uri(_url + "/id");
            Mock<CatchbaseUriBuilder>().Setup(b => b.Build<TestObject>("id")).Returns(uri);
            Subject.Get("id");
            Mock<RequestBuilder>().Verify(b => b.Build(It.IsAny<HttpMethod>(), uri), Times.Once());
        }

        [TestMethod]
        public void PostHandlesWebExceptionsThroughWebExceptionHandler()
        {
            _request.Setup(r => r.GetResponse()).Throws(new WebException());
            try
            {
                Subject.Post(new TestObject());
            }
            catch (WebException ex)
            {
                Mock<ExceptionHandler>().Verify(h => h.Handle(ex), Times.Once());
                return;
            }
            Assert.Fail();
        }

        [TestMethod]
        public void PostHandlesAllExceptionsThroughWebExceptionHandler()
        {
            _request.Setup(r => r.GetResponse()).Throws(new Exception());
            try
            {
                Subject.Post(new TestObject());
            }
            catch (Exception ex)
            {
                Mock<ExceptionHandler>().Verify(h => h.Handle(ex), Times.Once());
                return;
            }
            Assert.Fail();
        }


    }

    public class TestObject { }
}